package cn.wolfcode.web.controller;

import cn.wolfcode.common.web.CodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.config.AlipayProperties;
import cn.wolfcode.domain.PayResult;
import cn.wolfcode.domain.PayVo;
import cn.wolfcode.domain.RefundVo;
import cn.wolfcode.feign.SeckillFeignService;
import cn.wolfcode.util.AssertUtils;
import cn.wolfcode.web.msg.PayCodeMsg;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/alipay")
public class AlipayController {
    private final AlipayClient alipayClient;
    private final AlipayProperties alipayProperties;
    private final SeckillFeignService seckillFeignService;

    public AlipayController(AlipayClient alipayClient, AlipayProperties alipayProperties, SeckillFeignService seckillFeignService) {
        this.alipayClient = alipayClient;
        this.alipayProperties = alipayProperties;
        this.seckillFeignService = seckillFeignService;
    }

    @PostMapping("/refund")
    public Result<Boolean> refund(@RequestBody RefundVo refund) {
        log.info("[支付宝退款] 准备进行退款: {}", JSON.toJSONString(refund));
        AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();

        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(refund.getOutTradeNo());
        model.setRefundAmount(refund.getRefundAmount());
        model.setRefundReason(refund.getRefundReason());
        alipay_request.setBizModel(model);

        try {
            AlipayTradeRefundResponse response = alipayClient.execute(alipay_request);
            log.info("[支付宝退款] 收到支付宝退款响应消息: {}", JSON.toJSONString(response));
            AssertUtils.isTrue(response.isSuccess(), response.getSubMsg());

            // 判断是否支付成功
            if ("Y".equalsIgnoreCase(response.getFundChange())) {
                return Result.success(true);
            }

            // 如果 fund_change = N 应该再调用查询接口判断是否支付成功
            AlipayTradeFastpayRefundQueryRequest refundQueryRequest = new AlipayTradeFastpayRefundQueryRequest();

            AlipayTradeFastpayRefundQueryModel refundQueryModel = new AlipayTradeFastpayRefundQueryModel();
            refundQueryModel.setOutTradeNo(refund.getOutTradeNo());
            refundQueryModel.setOutRequestNo(refund.getOutTradeNo());
            alipay_request.setBizModel(model);

            AlipayTradeFastpayRefundQueryResponse refundQueryResponse = alipayClient.execute(refundQueryRequest);
            if ("10000".equals(refundQueryResponse.getCode()) && "REFUND_SUCCESS".equalsIgnoreCase(refundQueryResponse.getRefundStatus())) {
                return Result.success(true);
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return Result.error(new CodeMsg(506001, e.getMessage()));
        }

        return Result.success(false);
    }

    @GetMapping("/return_url")
    public void returnUrl(HttpServletRequest request, HttpServletResponse resp) {
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            params.put(name, valueStr);
        }

        try {
            log.info("[同步回调] 收到交易消息: {}", params);

            boolean verify_result = AlipaySignature.rsaCheckV1(params, alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(), "RSA2");
            AssertUtils.isTrue(verify_result, "支付宝回调签名验证失败");

            // 商户订单号
            String outTradeNo = request.getParameter("out_trade_no");

            resp.sendRedirect("http://localhost/order_detail.html?orderNo=" + outTradeNo);
        } catch (Exception e) {
            e.printStackTrace();
        }


        try {
            resp.getWriter().print("签名验证失败");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @PostMapping("/notify_url")
    public String notifyUrl(HttpServletRequest request) {

        // 接收支付宝的参数
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }

        try {
            log.info("[异步回调] 收到交易消息: {}", params);

            boolean verify_result = AlipaySignature.rsaCheckV1(params, alipayProperties.getAlipayPublicKey(),
                    alipayProperties.getCharset(), "RSA2");
            AssertUtils.isTrue(verify_result, "支付宝回调签名验证失败");

            //商户订单号
            String outTradeNo = request.getParameter("out_trade_no");
            //支付宝交易号
            String tradeNo = request.getParameter("trade_no");
            //交易状态
            String tradeStatus = request.getParameter("trade_status");
            // 支付金额
            String totalAmount = request.getParameter("total_amount");

            if (tradeStatus.equals("TRADE_FINISHED")) {
                log.info("[异步回调] {}订单已完成...", outTradeNo);
            } else if (tradeStatus.equals("TRADE_SUCCESS")) {
                log.info("[异步回调] {}订单已经支付成功", outTradeNo);
                // 远程调用秒杀服务更新订单状态
                PayResult result = new PayResult(outTradeNo, tradeNo, totalAmount);
                Result<?> ret = seckillFeignService.updateOrderPaySuccess(result);
                AssertUtils.isFalse(ret.hasError(), "更新订单支付成功失败");
            }

            return "success";
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        return "fail";
    }

    @PostMapping("/prepay")
    public Result<String> prepay(@RequestBody PayVo pay) {
        // 利用支付宝 SDK API 向支付宝发起支付请求
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

        /******必传参数******/
        JSONObject bizContent = new JSONObject();
        //商户订单号，商家自定义，保持唯一性
        bizContent.put("out_trade_no", pay.getOutTradeNo());
        //支付金额，最小值0.01元
        bizContent.put("total_amount", pay.getTotalAmount());
        //订单标题，不可使用特殊符号
        bizContent.put("subject", pay.getSubject());
        bizContent.put("body", pay.getBody());
        //电脑网站支付场景固定传值 FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

        request.setBizContent(bizContent.toString());
        //异步接收地址，仅支持http/https，公网可访问
        request.setNotifyUrl(alipayProperties.getNotifyUrl());
        //同步跳转地址，仅支持http/https
        request.setReturnUrl(alipayProperties.getReturnUrl());

        try {
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            if (response.isSuccess()) {
                String form = response.getBody();
                log.info("[支付宝支付] 发起支付成功, 收到支付响应结果: \n{}", form);
                return Result.success(form);
            }

            return Result.error(new CodeMsg(506001, response.getMsg()));
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return Result.error(PayCodeMsg.PAY_FAILED);
    }
}
